// SPDX-License-Identifier: MIT
// Copyright (C) 2018-present iced project and contributors

use crate::block_enc::tests::*;

const BITNESS: u32 = 64;
const ORIG_RIP: u64 = 0x8000;
const NEW_RIP: u64 = 0x8000_0000_0000_0000;
const DECODER_OPTIONS: u32 = super::DECODER_OPTIONS | DecoderOptions::KNC;

#[test]
fn jkcc_short_fwd() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x09,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x02,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
		/*000E*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x09,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x02,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
		/*000E*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0005,
		0x0007,
		0x000C,
		0x000E,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_short_bwd() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC4, 0xE0, 0x50, 0x74, 0xF9,// jkzd k5, short 0
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC4, 0xE0, 0x50, 0x75, 0xF2,// jknzd k5, short 0
		/*000E*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC4, 0xE0, 0x50, 0x74, 0xF9,// jkzd k5, short 0
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC4, 0xE0, 0x50, 0x75, 0xF2,// jknzd k5, short 0
		/*000E*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0002,
		0x0007,
		0x0009,
		0x000E,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_short_other_short() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x09,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x02,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x0A,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x03,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0005,
		0x0007,
		0x000C,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		ORIG_RIP - 1,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_short_other_near() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x09,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x02,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x07, 0xF0, 0xFF, 0xFF,// jkzd k5, near ptr 0Eh
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0xFE, 0xEF, 0xFF, 0xFF,// jknzd k5, near ptr 0Eh
		/*0010*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0007,
		0x0009,
		0x0010,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		ORIG_RIP + 0x1000,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_short_other_long() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x0B,// jkzd k5, short 10h
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x05,// jknzd k5, short 11h
		/*000C*/ 0xB0, 0x01,// mov al,1
		/*000E*/ 0x90,// nop
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x75, 0x06,// jknzd k5, short 8
		/*0005*/ 0xFF, 0x25, 0x15, 0x00, 0x00, 0x00,// jmp qword ptr [8000000000000020h]
		/*000B*/ 0xB0, 0x00,// mov al,0
		/*000D*/ 0xC4, 0xE0, 0x50, 0x74, 0x06,// jkzd k5, short 12
		/*0012*/ 0xFF, 0x25, 0x10, 0x00, 0x00, 0x00,// jmp qword ptr [8000000000000028h]
		/*0018*/ 0xB0, 0x01,// mov al,1
		/*001A*/ 0x90,// nop
		/*001B*/ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
		/*0020*/ 0x10, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
		/*0028*/ 0x11, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		u32::MAX,
		0x000B,
		u32::MAX,
		0x0018,
		0x001A,
	];
	#[rustfmt::skip]
	let expected_reloc_infos = [
		RelocInfo::new(RelocKind::Offset64, 0x8000_0000_0000_0020),
		RelocInfo::new(RelocKind::Offset64, 0x8000_0000_0000_0028),
	];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	const ORIG_RIP: u64 = 0x1234_5678_9ABC_DE00;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_fwd_short() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x0B, 0x00, 0x00, 0x00,// jkzd k5, near ptr 12h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x02, 0x00, 0x00, 0x00,// jknzd k5, near ptr 12h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x74, 0x09,// jkzd k5, short 0Eh
		/*0005*/ 0xB0, 0x00,// mov al,0
		/*0007*/ 0xC4, 0xE0, 0x50, 0x75, 0x02,// jknzd k5, short 0Eh
		/*000C*/ 0xB0, 0x01,// mov al,1
		/*000E*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0005,
		0x0007,
		0x000C,
		0x000E,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_fwd_near() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x8D, 0x00, 0x00, 0x00,// jkzd k5, near ptr 94h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x84, 0x00, 0x00, 0x00,// jknzd k5, near ptr 94h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*001F*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*002C*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0039*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0046*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0053*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0060*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*006D*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*007A*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0087*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0094*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x8D, 0x00, 0x00, 0x00,// jkzd k5, near ptr 94h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x84, 0x00, 0x00, 0x00,// jknzd k5, near ptr 94h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*001F*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*002C*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0039*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0046*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0053*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0060*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*006D*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*007A*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0087*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0094*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0007,
		0x0009,
		0x0010,
		0x0012,
		0x001F,
		0x002C,
		0x0039,
		0x0046,
		0x0053,
		0x0060,
		0x006D,
		0x007A,
		0x0087,
		0x0094,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_bwd_short() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC5, 0xD0, 0x84, 0xF7, 0xFF, 0xFF, 0xFF,// jkzd k5, near ptr 0
		/*0009*/ 0xB0, 0x00,// mov al,0
		/*000B*/ 0xC5, 0xD0, 0x85, 0xEE, 0xFF, 0xFF, 0xFF,// jknzd k5, near ptr 0
		/*0012*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC4, 0xE0, 0x50, 0x74, 0xF9,// jkzd k5, short 0
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC4, 0xE0, 0x50, 0x75, 0xF2,// jknzd k5, short 0
		/*000E*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0002,
		0x0007,
		0x0009,
		0x000E,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_bwd_near() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*000D*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*001A*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0027*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0034*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0041*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*004E*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*005B*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0068*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0075*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0082*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*008F*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*009C*/ 0xC5, 0xD0, 0x84, 0x5D, 0xFF, 0xFF, 0xFF,// jkzd k5, near ptr 0
		/*00A3*/ 0xB0, 0x00,// mov al,0
		/*00A5*/ 0xC5, 0xD0, 0x85, 0x54, 0xFF, 0xFF, 0xFF,// jknzd k5, near ptr 0
		/*00AC*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*000D*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*001A*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0027*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0034*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0041*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*004E*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*005B*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0068*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0075*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*0082*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*008F*/ 0x64, 0x67, 0xC7, 0x84, 0x0B, 0x78, 0x56, 0x34, 0x12, 0x78, 0x56, 0x34, 0x12,// mov dword ptr fs:[ebx+ecx+12345678h],12345678h
		/*009C*/ 0xC5, 0xD0, 0x84, 0x5D, 0xFF, 0xFF, 0xFF,// jkzd k5, near ptr 0
		/*00A3*/ 0xB0, 0x00,// mov al,0
		/*00A5*/ 0xC5, 0xD0, 0x85, 0x54, 0xFF, 0xFF, 0xFF,// jknzd k5, near ptr 0
		/*00AC*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x000D,
		0x001A,
		0x0027,
		0x0034,
		0x0041,
		0x004E,
		0x005B,
		0x0068,
		0x0075,
		0x0082,
		0x008F,
		0x009C,
		0x00A3,
		0x00A5,
		0x00AC,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_other_short() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC5, 0xD0, 0x84, 0x0B, 0x00, 0x00, 0x00,// jkzd k5, near ptr 14h
		/*0009*/ 0xB0, 0x00,// mov al,0
		/*000B*/ 0xC5, 0xD0, 0x85, 0x02, 0x00, 0x00, 0x00,// jknzd k5, near ptr 14h
		/*0012*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC4, 0xE0, 0x50, 0x74, 0x0E,// jkzd k5, short 0
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC4, 0xE0, 0x50, 0x75, 0x07,// jknzd k5, short 0
		/*000E*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0002,
		0x0007,
		0x0009,
		0x000E,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		ORIG_RIP - 1,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_other_near() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC5, 0xD0, 0x84, 0x0B, 0x00, 0x00, 0x00,// jkzd k5, near ptr 14h
		/*0009*/ 0xB0, 0x00,// mov al,0
		/*000B*/ 0xC5, 0xD0, 0x85, 0x02, 0x00, 0x00, 0x00,// jknzd k5, near ptr 14h
		/*0012*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xB0, 0x10,// mov al,10h
		/*0002*/ 0xC5, 0xD0, 0x84, 0x0B, 0xF0, 0xFF, 0xFF,// jkzd k5, near ptr 14h
		/*0009*/ 0xB0, 0x00,// mov al,0
		/*000B*/ 0xC5, 0xD0, 0x85, 0x02, 0xF0, 0xFF, 0xFF,// jknzd k5, near ptr 14h
		/*0012*/ 0xB0, 0x01,// mov al,1
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0002,
		0x0009,
		0x000B,
		0x0012,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		ORIG_RIP + 0x1000,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_other_long() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x0C, 0x00, 0x00, 0x00,// jkzd k5, near ptr 13h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x04, 0x00, 0x00, 0x00,// jknzd k5, near ptr 14h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0x90,// nop
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC4, 0xE0, 0x50, 0x75, 0x06,// jknzd k5, short 0Bh
		/*0005*/ 0xFF, 0x25, 0x15, 0x00, 0x00, 0x00,// jmp qword ptr [8000000000000020h]
		/*000B*/ 0xB0, 0x00,// mov al,0
		/*000D*/ 0xC4, 0xE0, 0x50, 0x74, 0x06,// jkzd k5, short 18h
		/*0012*/ 0xFF, 0x25, 0x10, 0x00, 0x00, 0x00,// jmp qword ptr [8000000000000028h]
		/*0018*/ 0xB0, 0x01,// mov al,1
		/*001A*/ 0x90,// nop
		/*001B*/ 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
		/*0020*/ 0x13, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
		/*0028*/ 0x14, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x34, 0x12,
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		u32::MAX,
		0x000B,
		u32::MAX,
		0x0018,
		0x001A,
	];
	#[rustfmt::skip]
	let expected_reloc_infos = [
		RelocInfo::new(RelocKind::Offset64, 0x8000_0000_0000_0020),
		RelocInfo::new(RelocKind::Offset64, 0x8000_0000_0000_0028),
	];
	const OPTIONS: u32 = BlockEncoderOptions::NONE;
	const ORIG_RIP: u64 = 0x1234_5678_9ABC_DE00;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}

#[test]
fn jkcc_near_fwd_short_no_opt() {
	#[rustfmt::skip]
	let original_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x0B, 0x00, 0x00, 0x00,// jkzd k5, near ptr 12h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x02, 0x00, 0x00, 0x00,// jknzd k5, near ptr 12h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let new_data = [
		/*0000*/ 0xC5, 0xD0, 0x84, 0x0B, 0x00, 0x00, 0x00,// jkzd k5, near ptr 12h
		/*0007*/ 0xB0, 0x00,// mov al,0
		/*0009*/ 0xC5, 0xD0, 0x85, 0x02, 0x00, 0x00, 0x00,// jknzd k5, near ptr 12h
		/*0010*/ 0xB0, 0x01,// mov al,1
		/*0012*/ 0xB0, 0x10,// mov al,10h
	];
	#[rustfmt::skip]
	let expected_instruction_offsets = [
		0x0000,
		0x0007,
		0x0009,
		0x0010,
		0x0012,
	];
	let expected_reloc_infos = [];
	const OPTIONS: u32 = BlockEncoderOptions::DONT_FIX_BRANCHES;
	encode_test(
		BITNESS,
		ORIG_RIP,
		&original_data,
		NEW_RIP,
		&new_data,
		OPTIONS,
		DECODER_OPTIONS,
		&expected_instruction_offsets,
		&expected_reloc_infos,
	);
}
